/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "单节点脚本.h"

#include <JIT.h>
#include "节点/socket_utils.h"
#include "节点/插座/通用插座.h"
#include "节点/插座/C_物体插座.h"
#include "节点/节点树.h"
#include "节点/输入输出节点.h"

#include "异步解算/物理异步解算.h"

#include "../../node后端.h"



C_函数节点::C_函数节点(S_设备环境& ctx, C_节点树* link_tree) : C_节点基类(DEF_函数节点, E_节点类型::e_节点Type_函数) {
	m_Name = L"函数";
	m_Ctx = ctx;
	m_函数指针 = 0;

	//C_插座基类* socket;
	m_编译运行 = f_alloc_BoolProp(nullptr, L"编译运行");
	m_编译运行.m_私有 = true;


	m_链接的节点树名称 = f_alloc_StrProp(nullptr, L"节点树名称");
	m_链接的节点树名称.m_私有 = true;

	
	if (link_tree) {
		f_绑定子节点树(link_tree);
		m_是否链接 = true;
	}
	else {
		auto* 子树 = f_node_Create函数节点树(false, L"fun_");
		f_绑定子节点树(子树);
		//m_子树->f_set父节点(this);
		m_是否链接 = false;

		auto 输入组节点 = new C_输入组节点(ctx);
		子树->f_添加节点(输入组节点);
		auto 输出组节点 = new C_输出组节点(ctx);
		子树->f_添加节点(输出组节点);

		输入组节点->m_插座可编辑 = true;
		输出组节点->m_插座可编辑 = true;

		输入组节点->m_坐标 = { -200, 0 };
		输出组节点->m_坐标 = {200, 0};
	}
	
	f_绑定this节点树(m_当前节点所在节点树);

	//m_更新方式 = E_节点更新方式::e_节点更新_被动;


	
}

C_函数节点::~C_函数节点() {
	f_prop_Release(m_链接的节点树名称);
	f_prop_Release(m_编译运行);
}

bool C_函数节点::f_update() {
	//if (m_子集节点树->m_节点结构改变) {
		m_InNodes.clear();
		m_OutNudes.clear();
		f_get子集输入节点(m_InNodes);
		f_get子集输出节点(m_OutNudes);
	//}

	for (auto& e : m_InNodes) {
		uint32 num = e->f_get输出插座Num();
		for (uint32 i = 0; i < num; ++i) {
			auto* socket = e->f_get输出插座(i);
			auto* inSocket = f_get输入插座(i);
			socket->f_setData(inSocket->f_getData(0));
		}
	}


	if (!m_子集节点树->m_程序集 || m_子集节点树->m_节点结构改变) {
		if (!m_子集节点树->m_开始编译) {
			m_函数指针 = nullptr;
			m_子集节点树->f_准备编译节点树();

			m_子集节点树->m_开始编译 = true;
			f_NodeCtx_物理模拟线程入栈(this);
		}
		return true;
	}
	else if (m_子集节点树->m_程序集 && !m_函数指针) {
		std::string 函数名称 = f_WStringToString(m_子集节点树->m_IDName);
		E_JIT方式 方式 = (E_JIT方式)f_prop_enum(m_子集节点树->m_编译方式);
		m_函数指针 = (expand_接口函数_函数节点)f_JIT_取函数指针(m_子集节点树->m_程序集, 函数名称, 方式);
	}


	if (m_函数指针) {
		std::vector<void*> inData;
		uint32 inNum = f_get输入插座Num();
		uint32 outNum = f_get输出插座Num();

		for (uint32 i = 0; i < inNum; ++i) {
			inData.emplace_back(f_get输入插座(i)->f_getData(0));
		}

		auto& 输入节点 = m_InNodes[0];
		for (uint32 i = 0; i < outNum; ++i) {
			std::string socketName = m_OutNudes[0]->f_get输入插座(i)->f_getCode(0);
			//std::string 输入插座代码 = 输入节点->f_get输出插座(i)->f_getCode();
			bool 是否输出插值引用输入插座 = false;
			uint32 socket_id = 0;
			for (; socket_id < inNum; ++socket_id) {
				//socketName = m_OutNudes[0]->f_get输入插座(socket_id)->f_getCode();
				std::string 输入插座代码 = 输入节点->f_get输出插座(socket_id)->f_getCode(0);

				if (socketName == 输入插座代码) {
					是否输出插值引用输入插座 = true;
					break;
				}
			}


			auto* socket = f_get输出插座(i);
			if (是否输出插值引用输入插座) {
				//socket->f_绑定指针(f_get输入插座(socket_id)->f_getData(0));
				socket->f_setData(f_get输入插座(socket_id)->f_getData(0));
			}
			else {
				socket->f_setData((void*)nullptr);
			}
			inData.emplace_back(f_get输出插座(i)->f_getData(0));
		}

		m_函数指针(inData.data(), C_节点树::g_节点JIT参数.data(), 0);
		//std::cout<< inData.size() << std::endl;
	}
	
	return false;
}

void C_函数节点::f_异步解算() {
	m_子集节点树->m_以编译 ^= E_节点树编译位标志::e_节点编译_外部调用;

	//std::string 函数名称 = f_WStringToString(f_prop_Str(m_子集节点树->m_函数名称));
	std::string 函数名称 = f_WStringToString(m_子集节点树->m_IDName);
	E_JIT方式 方式 = (E_JIT方式)f_prop_enum(m_子集节点树->m_编译方式);

	m_函数指针 = nullptr;
	m_编译成功 = true;

	std::string path = S_节点数据::g_工程文件函数节点代码绝对路径 + 函数名称 + ".cpp";
	bool 编译成功 = f_NT_编译节点(this, path, false);

	switch (方式) {
		case E_JIT方式::e_jit_llvm: path = f_file_get路径(S_节点数据::g_工程文件函数节点代码绝对路径) + 函数名称 + ".bc"; break;
		case E_JIT方式::e_jit_dll: path = f_file_get路径(S_节点数据::g_工程文件函数节点代码绝对路径) + 函数名称 + ".ex"; break;
	}


	m_子集节点树->m_开始编译 = false;
	if (编译成功 && f_file_文件是否存在(path)) {
		m_子集节点树->m_程序集 = f_JIT_加载代码(path, 方式);

		m_函数指针 = (expand_接口函数_函数节点)f_NT_初始化函数接口(m_子集节点树->m_程序集, 函数名称, 方式);
		if (!m_函数指针) {
			goto To_重新编译;
		}
		return;
	}
	else {
		To_重新编译:
		f_node_销毁程序集(m_子集节点树);
		m_编译成功 = false;
		std::cout << "编译函数错误" << std::endl;
	}

	f_set是否要更新(true);
}


void C_函数节点::f_get子集输入节点(std::vector<C_节点基类*>& inNodes) {
	inNodes.clear();
	for (auto& e : m_子集节点树->m_Nodes) {
		if (e->m_Type == E_节点类型::e_节点Type_组输入) {
			inNodes.emplace_back(e);
		}
	}
}

void C_函数节点::f_get子集输出节点(std::vector<C_节点基类*>& outNodes) {
	outNodes.clear();
	for (auto& e : m_子集节点树->m_Nodes) {
		if (e->m_Type == E_节点类型::e_节点Type_组输出) {
			outNodes.emplace_back(e);

			dynamic_cast<C_输出组节点*>(e)->m_输入节点 = m_InNodes.front();
		}

	}
}

std::string C_函数节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";
	
	std::string 返回参数定义释放;
	std::string name = f_WStringToString(m_子集节点树->m_IDName);
	std::string nodeName = f_getName();
	
	uint32 inNum = f_get输入插座Num();
	uint32 outNum = f_get输出插座Num();
	


	//C_节点树* rt = f_getThis节点树();

	bool 内联调用 = f_NT_是否内联调用(this);
	std::string extern_declspec;
	std::string 递归限制 = name + "_递归限制";


	bool 编译 = true;
	if (内联调用) {
		name += "_inline";

		if (m_子集节点树->m_以编译 & E_节点树编译位标志::e_节点编译_内联调用) {
			编译 = false;
		}
	}
	else {
		if (m_子集节点树->m_以编译 & E_节点树编译位标志::e_节点编译_外部调用) {
			编译 = false;
		}
	}


	f_get子集输入节点(m_InNodes);
	f_get子集输出节点(m_OutNudes);


	//m_子集节点树->m_编译状态锁.lock();
	if (编译) {
		m_函数声明 = "//" + f_getName() + "\n";
		m_函数声明 += " bool " + name + "(";

		if (内联调用) {
			m_子集节点树->m_以编译 |= E_节点树编译位标志::e_节点编译_内联调用;


			for (uint32 i = 1; i < inNum; ++i) {
				std::string 函数参数名称 = nodeName + "参数" + f_整数值转字符串(i);
				auto* socket = m_InNodes[0]->f_get输出插座(i);
				m_函数声明 += f_node_getDataTypeName(m_InNodes[0]->f_get输出插座(i)->m_Type);
				//m_函数声明 += " " + 函数参数名称;
				if (f_代码构建_数组指针(socket)) {
					m_函数声明 += "* " + 函数参数名称;
				}
				else {
					m_函数声明 += "& " + 函数参数名称;
				}

				m_InNodes[0]->f_get输出插座(i)->f_setCode(函数参数名称);
				m_函数声明 += ", ";
			}

			for (uint32 i = 1; i < outNum; ++i) {
				std::string 函数参数名称 = f_代码构建_节点树输出变量名称(m_OutNudes[0], i);
				auto* 输出节点的输入插座 = m_OutNudes[0]->f_get输入插座(i);

				m_函数声明 += f_node_getDataTypeName(输出节点的输入插座->m_Type);

				if (f_代码构建_数组指针(输出节点的输入插座)) {
					m_函数声明 += "* " + 函数参数名称;
				}
				else {
					m_函数声明 += "& " + 函数参数名称;
				}

				输出节点的输入插座->f_setCode(函数参数名称);
				m_函数声明 += ", ";
			}
			
		}
		else {
			m_子集节点树->m_以编译 |= E_节点树编译位标志::e_节点编译_外部调用;

			m_函数声明 += "void** inData, " DEF_S(DEF_编译可调参数) ", ";


			for (auto& e : m_InNodes) {
				for (uint32 i = 0; i < inNum; ++i) {
					auto* socket = f_get输入插座(i);

					e->f_get输出插座(i)->f_setCode(f_代码构建_节点树输入输出变量引用(socket->m_Type, i));
				}
			}

			for (auto& e : m_OutNudes) {
				for (uint32 i = 0; i < outNum; ++i) {
					//std::string 函数参数名称 = f_代码构建_节点树输出变量名称(e, i);
					auto* socket = f_get输出插座(i);
					
					f_get输出插座(i)->f_setCode(f_代码构建_节点树输入输出变量引用(socket->m_Type, i + inNum));
				}
				break;
			}
			
		}

		m_函数声明 += "uint32 " + 递归限制;
		m_函数声明 += ")";



		m_函数定义 = m_函数声明;
		m_函数定义 += "{\n";
		m_函数定义 += "if(" + 递归限制 + ">=8) return false;\n";



		if (内联调用) {
			//声明 += m_函数声明 + ";\n";

			//f_代码构建_添加JIT初始化函数指针()
		}
		else {
			extern_declspec = "extern \"C\" { __declspec(dllexport) ";

			声明 += "// ======== " + name + " ========\n";
			声明 += DEF_S(DEF_编译全局可调参数) " = nullptr;\n";
			声明 += extern_declspec + m_函数声明 + ";}\n";

			m_函数定义 += DEF_S(DEF_编译全局可调参数赋值)";\n";


			for (auto& e : m_OutNudes) {
				for (uint32 i = 0; i < outNum; ++i) {
					auto* socket = f_get输出插座(i);
					//auto* 输出节点的输入插座 = e->f_get输入插座(i);
					//dynamic_cast<C_输出组节点*>(e)->m_输入节点->f_get输出插座(i);

					if (f_代码构建_数组指针(socket)) {
						m_函数定义 += "auto* ";
					}
					else {
						m_函数定义 += "auto& ";
					}
					//m_函数定义 += f_代码构建_节点树输出变量名称(m_子集节点树, i);
					//m_函数定义 += 输出节点的输入插座->f_getCode();
					m_函数定义 += f_代码构建_节点树输出变量名称(m_OutNudes[0], i);
					m_函数定义 += " = " + f_get输出插座(i)->f_getCode(0) + ";\n";
				}
			}
		}

		
		m_函数定义 += f_NT_编译节点树(m_子集节点树, 定义, 声明);


		m_函数定义 += "return true;\n";
		m_函数定义 += "}\n";
		
		
		if (内联调用) {
			f_代码构建_内联函数声明定义(name, m_函数声明 + ";\n", m_函数定义);
		}
		else {
			定义.push_back(m_函数定义);
		}
	}





	if (内联调用) {
		
		for (uint32 i = 0; i < inNum; ++i) {
			m_Code += f_get输入插座(i)->f_构建变量代码(0);
		}
		std::string 返回参数定义;


		for (uint32 i = 1; i < outNum; ++i) {
			bool 是否输出插值引用输入插座 = false;

			std::string socketName = m_OutNudes[0]->f_get输入插座(i)->f_getCode(0);
			
			auto& 输入节点 = m_InNodes.front();
			for (uint32 socket_id = 1; socket_id < inNum; ++socket_id) {
				std::string 输入插座代码 = 输入节点->f_get输出插座(socket_id)->f_getCode(0);

				if (socketName == 输入插座代码) {
					socketName = f_get输入插座(socket_id)->f_getCode(0);
					//std::cout << "参数名称:" << socketName << std::endl;
					是否输出插值引用输入插座 = true;
					break;
				}
			}
			
			

			auto* socket = f_get输出插座(i);
			if (是否输出插值引用输入插座) {
				socket->f_setCode(socketName);
				//std::cout<<"输出引用"<<std::endl;
				continue;
			}

			//m_Code += f_get输出插座(i)->f_构建变量代码();
			
			socketName = nodeName + socket->f_getName() + "_ren_" + f_整数值转字符串(i);
			socket->f_setCode(socketName);

			返回参数定义 += f_node_getDataTypeName(socket->m_Type);
			switch (socket->m_Type) {
				case E_值类型::e_Type_I8:
				case E_值类型::e_Type_F32:
				case E_值类型::e_Type_I32:
				case E_值类型::e_Type_UI32:
					返回参数定义 += " " + socketName + " = 0;\n";
					break;
				case E_值类型::e_Type_Vec2:
				case E_值类型::e_Type_uVec2:
					返回参数定义 += " " + socketName + " = {0,0};\n";
					break;
				case E_值类型::e_Type_Vec3:
				case E_值类型::e_Type_iVec3:
				case E_值类型::e_Type_uVec3:
					返回参数定义 += " " + socketName + " = {0,0,0};\n";
					break;
				case E_值类型::e_Type_Vec4:
				case E_值类型::e_Type_iVec4:
				case E_值类型::e_Type_uVec4:
					返回参数定义 += " " + socketName + " = {0,0,0,0};\n";
					break;
				case E_值类型::e_Type_多边形边:
					返回参数定义 += "* " + socketName + " = nullptr;\n";
					break;
				default:
					返回参数定义 += "* " + socketName + " = " + f_代码构建_创建Array(socket->m_Type, "0") + ";\n";
					返回参数定义释放 += f_代码构建_销毁数组(socketName);
					break;
			}
		}




		//函数调用代码
		m_Code += 返回参数定义;
		m_Code += name + "(";

		for (uint32 i = 1; i < inNum; ++i) {
			auto 参数代码 = f_get输入插座(i)->f_getCode(0);
			m_Code += f_get输入插座(i)->f_getCode(0) + ", ";

			if (参数代码.empty()) {
				m_编译成功 = false;
			}
		}

		for (uint32 i = 1; i < outNum; ++i) {
			auto* socket = f_get输出插座(i);
			m_Code += socket->f_getCode(0) + ", ";
		}


		if (m_当前节点所在节点树 == m_子集节点树) {
			m_Code += 递归限制 + "+1";
		}
		else {
			m_Code += "0";
		}

		m_Code += ");\n";
		m_Code += m_ReleaseCode;
		//m_Code = 返回参数定义 + m_Code;
	}


	//m_子集节点树->m_编译状态锁.unlock();

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		m_区域父节点->m_ReleaseCode += 返回参数定义释放;
		return "";
	}
	释放 += 返回参数定义释放;
	return m_Code;
}

void C_函数节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	f_prop_Load(m_编译运行, f);

	fread(&m_是否链接, sizeof(bool), 1, f);

}

void C_函数节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	f_prop_Save(m_编译运行, f);

	fwrite(&m_是否链接, sizeof(bool), 1, f);

}

inline void C_函数节点::f_绑定子节点树(C_节点树* tree) {
	C_节点基类::f_绑定子集节点树(tree);
	f_prop_Str(m_链接的节点树名称) = tree->m_IDName;
}

S_物体* C_函数节点::f_get虚拟体() {
	uint32 num = f_get输出插座Num();
	for (uint32 i = 1; i < num; ++i) {
		auto* socket = f_get输出插座(i);
		switch (socket->m_Type) {
			case E_值类型::e_Type_Object:
				return DEF_物体插座数据(socket, 0);
		}
	}
	return nullptr;
}

void C_函数节点::f_入回收() {
	//m_子集节点树->m_节点树绑定的父节点.erase(this);
}

void C_函数节点::f_回收() {
	//m_子集节点树->m_节点树绑定的父节点.insert(this);
}

void C_函数节点::f_Copy(const C_节点基类* node) {
}


C_节点基类* f_node_创建函数节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_函数节点(ctx, 子节点树);
}

C_节点基类* f_node_加载函数节点(S_设备环境& ctx, FILE* f) {
	std::wstring 链接的节点树名称 = f_file_读取字符串(f);

	if (S_节点数据::G用于重新映射节点树到节点的容器.find(链接的节点树名称) == S_节点数据::G用于重新映射节点树到节点的容器.end()) {
		f_node_加载节点树(ctx, f);
	}

	C_函数节点* node = new C_函数节点(ctx, S_节点数据::G用于重新映射节点树到节点的容器[链接的节点树名称]);
	return node;
}

void f_node_保存函数节点(C_节点基类* n, FILE* f) {
	C_函数节点* node = static_cast<C_函数节点*>(n);

	auto* tree = node->f_get子集树();
	f_file_保存字符串(f, tree->m_IDName);

	if (tree->m_未保存或加载) {
		tree->m_未保存或加载 = false;

		std::vector<C_节点树*> trees = { tree };
		f_node_保存节点树(trees, f);
	}
}




C_Python节点::C_Python节点(S_设备环境& ctx) : C_节点基类(DEF_Python节点) {
	m_Name = L"Python";
	m_Ctx = ctx;

	auto* 子树 = f_node_Create节点树(false, L"Python");
	f_绑定子集节点树(子树);
	//子树->f_set父节点(this);

	子树->f_添加节点(new C_输入组节点(ctx));
	子树->f_添加节点(new C_输出组节点(ctx));

	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;

	m_FilePath = f_alloc_PathProp(nullptr, L"文件路径");
	m_FilePath.m_私有 = true;

}

C_Python节点::~C_Python节点() {
}

bool C_Python节点::f_update() {
	if (m_子集节点树->m_节点结构改变) {
		m_InNodes.clear();
		m_OutNudes.clear();
		f_get子集输入节点(m_InNodes);
		f_get子集输入节点(m_OutNudes);
	}

	f_NT_StepUpdate节点(m_子集节点树, true);

	auto path = f_prop_Path(m_FilePath).wstring();



	return false;
}

void C_Python节点::f_get子集输入节点(std::vector<C_节点基类*>& inNodes) {
	for (auto& e : m_子集节点树->m_Nodes) {
		if (e->m_Type == E_节点类型::e_节点Type_组输入) {
			inNodes.emplace_back(e);
		}
	}
}

void C_Python节点::f_get子集输出节点(std::vector<C_节点基类*>& outNodes) {
	for (auto& e : m_子集节点树->m_Nodes) {
		if (e->m_Type == E_节点类型::e_节点Type_组输出) {
			outNodes.emplace_back(e);
		}
	}
}

void C_Python节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_FilePath, f);
}

void C_Python节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_FilePath, f);
}

C_节点基类* f_node_加载Python节点(S_设备环境& ctx, FILE* f) {
	C_Python节点* node = new C_Python节点(ctx);
	return node;
}

void f_node_保存Python节点(C_节点基类* n, FILE* f) {
	C_Python节点* node = static_cast<C_Python节点*>(n);
}




C_结构节点::C_结构节点(S_设备环境& ctx, C_节点树* link_tree) : C_节点基类(DEF_结构节点, E_节点类型::e_节点Type_结构) {
	m_Name = L"结构";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建引用插座_I(L"a");
	DEF_创建引用插座_O(L"b");
}

C_结构节点::~C_结构节点() {
	
}

bool C_结构节点::f_update() {
	return false;
}

std::string C_结构节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";



	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		return "";
	}
	return m_Code;
}

void C_结构节点::f_异步解算() {
	
}

void C_结构节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_0, S_节点数据::g_文件版本号)) {
			//下一次读取数据指针 = f_prop_Load(m_UV类型, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_结构节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_UV类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

void C_结构节点::f_Copy(const C_节点基类* node) {
	
}

C_节点基类* f_node_创建结构节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_结构节点(ctx, 子节点树);
}
C_节点基类* f_node_加载结构节点(S_设备环境& ctx, FILE* f) {
	C_结构节点* node = new C_结构节点(ctx, nullptr);
	return node;
}
void f_node_保存结构节点(C_节点基类* n, FILE* f) {
	C_结构节点* node = static_cast<C_结构节点*>(n);
}





